package com.miyake.dsp.osa.lab;

import java.util.ArrayList;
import java.util.List;

import com.miyake.dsp.ComplexArray;
import com.miyake.dsp.common.CommonTool;
import com.miyake.dsp.generator.GaussGenerator;
import com.miyake.dsp.generator.NoiseGenerator;
import com.miyake.dsp.generator.NoiseSetting;
import com.miyake.dsp.ui.LineChartPanel;

public class NoiseDetector2 {

	public List<Integer> getIndexCandicates() {
		return indexCandicates;
	}

	public double[] getLaplacian() {
		return laplacian;
	}

	public double[] getSortedLaplacian() {
		return sortedLaplacian;
	}

	public double[] getSortedDiff() {
		return sortedDiff;
	}

	public List<Double> getCandicates() {
		return candicates;
	}

	public double[] getDiff() {
		return diff;
	}

	public static void main(String[] arg) {
		
/*		GaussGenerator gauss = new GaussGenerator(1, 0, 1001, 20);
		double[] data = gauss.getY();
		*/
		
		double[] data = new double[1000];
		for (int i = 0; i < data.length; i++) {
			if (i > 100 && i < 200) {
				data[i] = 1;
			}
			if (i >= 200 && i < 300) {
				data[i] = 2;
			}
			if (i >= 300 && i < 400) {
				data[i] = 20;
			}
			if (i >= 400 && i < 500) {
				data[i] = 6;
			}
			if (i >= 500 && i < 600) {
				data[i] = 8;
			}
		}
		data = CommonTool.getSmoothed(data, 20);
		
		NoiseGenerator noise = new NoiseGenerator(new NoiseSetting(10e-1));
		noise.setSource(new ComplexArray(data));
		double[] d = noise.getProcessed().getRealPart();
		NoiseDetector2 detector = new NoiseDetector2(d);
		
		LineChartPanel chart = LineChartPanel.createChart();
		chart.updateUI();
		chart.setData("sorted", detector.getSorted());
		double[] y = new double[1];
		//y[0] = detector.getNoiseLevel();
		chart.addYMarker(detector.getCandicates());
		chart.setData("Diff", CommonTool.getGained(detector.getDiff(), 20));
		chart.setData("Lap", CommonTool.getGained(detector.getLaplacian(), 20));
//		chart.setData("Sorted Diff", detector.sortedDiff);
//		chart.setData("Sorted Lap", detector.getSortedLaplacian());
		chart.setData("Data", d);
	}
	
	private double noiseLevel;
	private double[] sorted;
	private double[] diff;
	private List<Double> candicates = new ArrayList<Double>();
	private List<Integer> indexCandicates = new ArrayList<Integer>();
	private double[] sortedDiff;
	private double[] sortedLaplacian;
	private double[] laplacian;
	
	enum Status {
		OUTOF_EDGE,
		BEGIN_EDGE,
		IN_EDGE,
	}
	public NoiseDetector2(double[] data) {
		// Sort
		Sort sort = new Sort(data);
		
		sorted = CommonTool.getSmoothed(sort.getOuty(), sort.getOuty().length / 50);
			
		diff = CommonTool.getDiff(sorted);
		laplacian = CommonTool.getDiff(CommonTool.getSmoothed(diff, diff.length/50));
		//laplacian = CommonTool.getDiff(diff);
		Sort sort2 = new Sort(diff);
		sortedDiff = sort2.getOuty();
		
		sortedLaplacian = CommonTool.getDiff(sortedDiff);
	//	LineChartPanel.showChart(sortedDiff, "diff");
		double threshold = CommonTool.getMaxValue(sortedDiff, 0, sortedDiff.length/10);
		threshold *= 2.0;

//		int index = 0;
		Status status = Status.OUTOF_EDGE;
		for (int i = 0; i < diff.length -1; i++) {
			if (status.equals(Status.OUTOF_EDGE)) {
				if (diff[i] > threshold) {
					addEdge(data, sort.getOutXindex()[i]);
					status = Status.BEGIN_EDGE;
				}
			}
			else if (status.equals(Status.BEGIN_EDGE)) {
				if (laplacian[i] < 0) {
					status = Status.IN_EDGE;
				}
			}
			else if (status.equals(Status.IN_EDGE)) {
				if (diff[i] < threshold) {
					//addEdge(data, sort.getOutXindex()[i]);
				}
				if (laplacian[i] > 0) {
					status = Status.OUTOF_EDGE;
					//threshold += diff[i];
					threshold = CommonTool.getMaxValue(diff, i, i+diff.length/100) *1.5;
					//addEdge(data, sort.getOutXindex()[i]);
				}
			}
			
		}
		for (Double v : this.candicates) {
			if (v > data[0]) {
				noiseLevel = v;
				break;
			}
		}

	}

	private void addEdge(double[] data, int index) {
		candicates.add(data[index]);
		indexCandicates.add(index);
	}
	
	public double getNoiseLevel() {
		return noiseLevel;
	}
	
	public double[] getSorted() {
		return this.sorted;
	}
}
